package cc.verywell.pureblock.func;

import java.util.HashMap;

import cc.verywell.pureblock.util.unsafe.UnsafeRun;

/**
* 
	 * <p>PureBlock 每对链接都可以支持不同的功能组合，这让PureBlock 可以细分成各种功能机，
	 * 比如专用的矿机，专用的网络中继器，专用的显示终端，及各种功能界面等。
	 * 考虑到自定义扩展，用固定的数字编号的话，分配起来会比较麻烦。
	 * 现在使用255bytes(UTF-8)或以内的功能名，系统会在每对链接initMsg后自动为这些功能编号。
	 * 但为了快速知道功能在每对不同链接的编号，需要为这些功能做索引，本接口就是这么一个东西.</p>
	 * 如果您有更好的索引方案，可以像这样重载本类;
	 * <p> <b>Usage Example:</b> </p>
	 * <pre>
	 * FuncProviderManager.funcIndex = new new FuncIndexGenerator(){
		private int currentList;
		public FuncIndex getFuncIndex(FuncProvider[] list) {
			//TODO your code to return FuncIndex;
			return myFuncIndex;
		}
	};</pre>
	 * 
* 
* Copyright 2019 TanYaqiu
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月17日 下午8:57:40
*/
public interface FuncIndex {
	/**
	 * 
	 * @param provider a FuncProvider 
	 * @return FuncProvider at this session's index, the index use to encode {@link cc.verywell.pureblock.net.Msg};
	 */
	abstract public int getFuncProviderIndex(FuncProvider provider);
	/**
	 * 
	 * @param provider a FuncProvider 
	 * @return true if FuncProvider used in this session;  
	 */
	abstract public boolean isFuncProviderExist(FuncProvider provider);
	
	
	
	/////以下为生成器内容
	
	/**
	 * 自编接口,用来实现FuncIndex
	 */
	static public interface FuncIndexGenerator{
		/**
		 * 
		 * @param list FuncProvider[]: the func we used in this channel
		 * @param isFullList boolean: is used all func
		 * @return FuncIndex that supply {@link FuncIndex#getFuncProviderIndex} and {@link FuncIndex#isFuncProviderExist}
		 */
		public FuncIndex getFuncIndex(FuncProvider[] list, boolean isFullList);
	}
	static public class DefaultFuncIndexGenerator implements FuncIndexGenerator{
		private int currentList = -1;
		private FuncIndex cached;
		public FuncIndex getFuncIndex(FuncProvider[] list, boolean isFullList) {
			int maxIndex = isFullList?list.length-1:getMaxIndex(list);
			if(list.length==maxIndex && list.length==currentList) {
				synchronized (this) {
					if(list.length==currentList && maxIndex==currentList) {
						return cached;
					}
				}
			}
			FuncIndex fi;
			if(list.length<=5 && maxIndex>0xFFFE) {
				fi = new DirtyHack(list);
			}else if(list.length<0xFE) {
				if(maxIndex<0xFE || maxIndex<list.length*UnsafeRun.MemoryAddressSize*3) {
					fi = new ByteIndex(list, maxIndex);
				}else {
					fi = new MapIndex(list);
				}
			}else if(list.length<0xFFFE) {
				if(maxIndex<0xFFFE || maxIndex*2<list.length*UnsafeRun.MemoryAddressSize*3) {
					fi = new ByteIndex(list, maxIndex);
				}else {
					fi = new MapIndex(list);
				}
			}else {
				fi = new MapIndex(list);
			}
			if(list.length==maxIndex && list.length>currentList) {
				synchronized (this) {
					if(list.length==currentList && maxIndex==currentList) {
						cached = fi;
					}
				}
			}
			return fi;
		}
	};

	/**
	 * @param FuncProvider[] list
	 * @return 列表中最大的index;
	 */
	public static int getMaxIndex(FuncProvider[] list) {
		int maxIndex = -1;
		for (FuncProvider f : list) {
			int i = f.getIndex();
			if(i>maxIndex)maxIndex = i;//(a >= b) ? a : b;;
		}
		return maxIndex;
	}
	
	//以下是各种实现类

	/**
	 * 以下2个索引都是一样的, 只是short和byte不同
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 */
	public static class ShortIndex implements FuncIndex{
		final private short[] index;
		public ShortIndex(FuncProvider[] list,int maxIndex) {
			if(list.length>0xFFFE)throw new IllegalAccessError("ShortIndex only accept FuncProvider[].length<65535.");
			index = new short[maxIndex+1];
			short j = 1;
			for (int i = 0; i < list.length; i++) {
				index[list[i].getIndex()] = j++;
			}
		}
		@Override
		public int getFuncProviderIndex(FuncProvider provider) {
			int i = provider.getIndex();
			return (i<index.length)?(0xFFFF&index[i]-1):-1;
		}
		@Override
		public boolean isFuncProviderExist(FuncProvider provider) {
			int i = provider.getIndex();
			return (i<index.length)?(index[i]!=0):false;
		}
	}
	public static class ByteIndex implements FuncIndex{
		final private byte[] index;
		public ByteIndex(FuncProvider[] list,int maxIndex) {
			if(list.length>0xFE)throw new IllegalAccessError("ByteIndex only accept FuncProvider[].length<255.");
			index = new byte[maxIndex+1];
			byte j = 1;
			for (int i = 0; i < list.length; i++) {
				index[list[i].getIndex()] = j++;
			}
		}
		@Override
		public int getFuncProviderIndex(FuncProvider provider) {
			int i = provider.getIndex();
			return (i<index.length)?(0xFF&index[i]-1):-1;
		}
		@Override
		public boolean isFuncProviderExist(FuncProvider provider) {
			int i = provider.getIndex();
			return (i<index.length)?(index[i]!=0):false;
		}
	}
	
	/**
	 * hashMap索引, 真要遇到用它的情况，大家还是接数据库吧。
	 * Copyright 2019 TanYaqiu
	 * @author TanYaqiu 
	 */
	static class MapIndex implements FuncIndex{
		final private HashMap<Integer,Integer> map;
		public MapIndex(FuncProvider[] list) {
			map = new HashMap<Integer,Integer>(list.length);
			int i = 0;
			for (FuncProvider f : list) {
				map.put(f.getIndex(), i++);
			}
		}
		@Override
		public int getFuncProviderIndex(FuncProvider provider) {
			Integer i = map.get(provider.getIndex());
			return (i!=null)?i:-1;
		}
		@Override
		public boolean isFuncProviderExist(FuncProvider provider) {
			Integer i = map.get(provider.getIndex());
			return i!=null;
		}
	}
	
	/**
	 * (2019-03-16)
	 * such a dirty hack;
	 * 太难看了，有好方案请不吝留言赐教啊！
	 * 暂时就当作是发送的成本吧。
	 */
	@Deprecated
	static class DirtyHack implements FuncIndex{
		final private FuncProvider[] list;
		public DirtyHack(FuncProvider[] list) {
			this.list = list;
		}
		@Override
		public int getFuncProviderIndex(FuncProvider provider) {
			for (int i = 0; i < list.length; i++) {
				if(provider==list[i]) return i;
			}
			return -1;
		}
		@Override
		public boolean isFuncProviderExist(FuncProvider provider) {
			return 0<=getFuncProviderIndex(provider);
		}
	}
	
	
	
}
